#include "MIBS.h"
#include "error_insert_help.h"

#include <stdio.h>
#include <stdlib.h>
#include <string>

typedef struct
{
	error_struct data[LIST_MAX] ;
	int size ;
}error_data_list;

static error_data_list error_list ;
static int error_list_initialled ;

static void list_initial( error_data_list* list )
{
	list->size = 0 ;
}

static inline int list_size( error_data_list* list) 
{
	return list->size ;
}

static int list_full( error_data_list* list )
{
	return (list->size == LIST_MAX) ;
}

static int list_empty( error_data_list* list )
{
	return (list->size == 0) ;
}

static int list_add_by_round_order( error_data_list* list , error_struct* data )
{
	if ( list_full(list) )
	{
		return 0 ;
	}
	else
	{
		int insert_pos = list->size - 1 ;
		for ( ; insert_pos >= 0 ; --insert_pos )
		{
			if ( list->data[insert_pos].round <= data->round )
			{
				break ;
			}
			memcpy( list->data + insert_pos + 1 , list->data + insert_pos , sizeof(error_struct) ) ;
		}
		memcpy( list->data + insert_pos + 1 , data , sizeof(error_struct) ) ;
		++list->size ;
		return 1 ;
	}
}

int add_error_struct( error_struct* error_data )
{
	if ( error_list_initialled == 0 )
	{
		list_initial( &error_list ) ;
		error_list_initialled = 1 ;
	}
	if ( !list_add_by_round_order(&error_list , error_data)) 
	{
		return 0 ;
	}
	return 1 ;
}

void clear_error_struct()
{
	list_initial( &error_list ) ;
	error_list_initialled = 1 ;
}

void error_insert_hook_func( nibble state[] , const int n , int round )
{
	int examined_pos = 0 ;
	for ( ; examined_pos < list_size(&error_list) ; ++examined_pos )
	{
		if ( error_list.data[examined_pos].round > round )
			break ;
		else if ( error_list.data[examined_pos].round == round )
		{
			error_list.data[examined_pos].apply_func(&error_list.data[examined_pos] , state , n ) ;
		}
		else
		{
			//should not reach here!
		}
	}
}

void xor_error_apply( void* this_ptr , nibble state[] , const int n )
{
	int i = 0 ;
	error_struct* error_data = (error_struct*)this_ptr ;
	union temp_data
	{
		nibble nibble_value ;
		byte byte_value ;
		word word_value ;
	};
	if ( error_data->size == 4 )
	{
		//		error_data->data.nibble_val = temp_data.byte_value ;
		state[error_data->pos] = error_data->word_val ^ state[error_data->pos] ;
	}
	if ( error_data->size == 8 )
	{
		//		error_data->data.byte_val = temp_data.byte_value ;
		state[(error_data->pos)*2] = state[(error_data->pos)*2] ^ (((error_data->word_val)>>4)&0x0f) ;
		state[(error_data->pos)*2+1] = state[(error_data->pos)*2+1] ^ ((error_data->word_val)&0x0f) ;
	}
	if ( error_data->size == 32 )
	{
		//		error_data->data.word_val = temp_data.word_value ;
		for ( i = 0 ; i < MIBS_KEY_NIBBLE ; ++i )
		{
			state[(error_data->pos)*8+i] = ((error_data->word_val)>>(4*(7-i))) & 0x0f ;
		}
	}
}